#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include "fpe.h"

void hex2chars(unsigned char hex[], unsigned char result[])//把相邻两个字符合成一个16进制
{
    int len = strlen(hex);
    unsigned char temp[3];
    temp[2] = 0x00;

    int j = 0;
    for (int i = 0; i < len; i += 2) {
        temp[0] = hex[i];
        temp[1] = hex[i + 1];
        result[j] = (char)strtol(temp, NULL, 16);
        ++j;
    }
}

void map_chars(unsigned char str[], unsigned int result[])//把一个字符转成一个数字
{
    int len = strlen(str);

    for (int i = 0; i < len; ++i)
        if (str[i] >= 'a')
            result[i] = str[i] - 'a' + 10;
        else
            result[i] = str[i] - '0';
}

void inverse_map_chars(unsigned result[], unsigned char str[], int len)//把一个数字转成一个字符
{
    for (int i = 0; i < len; ++i)
        if (result[i] < 10)
            str[i] = result[i] + '0';
        else
            str[i] = result[i] - 10 + 'a';

    str[len] = 0x00;
}

int main()
{
	char default_tweak[] = "0000000000000000";//默认口令
	char default_key[] = "EF4359D8D580AA4F7F036D6F04FC6A94";//默认秘钥
	char default_radix[] = "36";//默认基数

	while (1)
	{
		char origin[1000];
		printf("Input a string(length<1000, only consists of a-z and 0-9, '#' to quit):\n");
		scanf("%s", origin);//接收输入字符串
		if (origin[0] == '#')//判断结束条件
			break;

		int flag = 1;
		for (int i = 0; i < strlen(origin); ++i)
		{
			char c = origin[i];
			if (isalnum(c) == 0)//是否是字母或数字
			{
				printf("Input contains illegal characters!\n");
				flag = 0;
				break;
			}
			if (c >= 'A'&&c <= 'Z')//输入字符不在固定范围内
			{
				printf("Input contains illegal characters!\n");
				flag = 0;
				break;
			}
		}

		if (0 == flag)//输入了无效数据，不再往下执行
			continue;

		unsigned char k[100],
			t[100],
			result[100];
		int xlen = strlen(origin), //原始数据长度
			klen = strlen(default_key) / 2, //默认秘钥长度的一半
			tlen = strlen(default_tweak) / 2,
			radix = atoi(default_radix);//把数字字符转换成数字
		unsigned int x[100];
		unsigned int* y;
		y = (unsigned int*)malloc(xlen * 8);//动态申请内存
		unsigned int tmp;

		hex2chars(default_radix, k);//把每个字符转换成一个字节
		hex2chars(default_tweak, t);
		map_chars(origin, x);//把每个字符转换成一个数字

		for (int i = 0; i < xlen; ++i)
			assert(x[i] < radix);//大于radix就抛出异常

		FPE_KEY ff3;//对应的是struct fpe_key_st结构体


		FPE_set_ff3_key(k, klen * 8, t, radix, &ff3);//设置加密密钥

		printf("-------------ENCRYPTION-------------\n");
		FPE_ff3_encrypt(x, y, xlen, &ff3, FPE_ENCRYPT);//加密

		printf("ciphertext(numeral string):");
		for (int i = 0; i < xlen; ++i)    printf("%d", y[i]);//输出加密数字结果
		printf("\n");

		inverse_map_chars(y, result, xlen);//把数字转出字符
		printf("ciphertext: %s\n\n", result);//输出加密字符串结果

		printf("-------------DECRYPTION-------------\n");
		//Set to zero for x
		memset(x, 0, sizeof(x));
		FPE_ff3_encrypt(y, x, xlen, &ff3, FPE_DECRYPT);//解密

		printf("plaintext:");
		for (int i = 0; i < xlen; ++i)    printf("%d", x[i]);//输出解密数字结果
		printf("\n");

		inverse_map_chars(x, result, xlen);//把数字转出字符
		printf("deciphertext: %s\n\n", result);//输出解密字符串结果

		FPE_unset_ff3_key(&ff3);//释放资源

		free(y);//释放内存
	}

    return 0;
}

